﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;

using Invini.Training.Logging;

namespace Invini.Training
{
    public delegate void TrainingSessionCompletedEventHandler(TrainingSession trainingSession);

    public class TrainingSession
    {
        public event TrainingSessionCompletedEventHandler Completed;

        private ITrainingScript script;
        private Stopwatch timer = new Stopwatch();
        private Dictionary<TrainingTriggerBase, TriggerLogItem> logItems;
        private object logItemsLock = new object();

        private SessionLog _log;
        public SessionLog Log
        {
            get { return this._log; }
        }

        public ITrainingScript Script
        {
            get { return this.script; }
        }

        public TrainingSession(ITrainingScript script)
        {
            if (script == null)
                throw new ArgumentNullException("script");

            this.script = script;
            this.script.Completed += this.scriptCompleted;
            this.script.TriggerStarted += this.triggerStarted;
            this.script.TriggerCompleted += this.triggerCompleted;
            this.script.TriggerConditionSatisfied += this.triggerConditionSatisfied;
        }

        public void Start()
        {
            this.logItems = new Dictionary<TrainingTriggerBase, TriggerLogItem>();
            this._log = new SessionLog(this.script.Name, DateTime.UtcNow);

            this.timer.Start();
            this.script.Execute();
        }
        private void scriptCompleted(ITrainingScript trainingScript)
        {
            this.timer.Stop();

            this.logItems = null;

            if (this.Completed != null)
                this.Completed(this);
        }
        private void triggerStarted(TrainingTriggerBase trainingTrigger)
        {
            TriggerLogItem logItem = this.getLogItem(trainingTrigger);
            logItem.StartedOffset = this.timer.Elapsed.TotalSeconds;
        }
        private void triggerCompleted(TrainingTriggerBase trainingTrigger)
        {
            TriggerLogItem logItem = this.getLogItem(trainingTrigger);
            logItem.CompletedOffset = this.timer.Elapsed.TotalSeconds;
        }
        private void triggerConditionSatisfied(TrainingTriggerBase trainingTrigger)
        {
            TriggerLogItem logItem = this.getLogItem(trainingTrigger);
            logItem.ConditionSatisfiedOffset = this.timer.Elapsed.TotalSeconds;
        }

        private TriggerLogItem getLogItem(TrainingTriggerBase trainingTrigger)
        {
            lock(this.logItemsLock)
            {
                if (this.logItems.ContainsKey(trainingTrigger))
                    return this.logItems[trainingTrigger];

                TriggerLogItem logItem = new TriggerLogItem(trainingTrigger.Name);
                this.logItems.Add(trainingTrigger, logItem);
                this._log.AddItem(logItem);

                return logItem;
            }
        }
    }
}
